#!/usr/bin/env python

from __future__ import division
""" Tremulous Clientside Statistics """
__version__ = 73
__author__ = """Durand - durand1@gmail.com"""
__credits__ = """elf@tm and Morte for beta testing
Basilisco for the great icons: http://wilhelmrahn.googlepages.com/tremulousstuff
Paradox for the battlesuit icon: http://paradox460.deviantart.com/art/Tremulous-icons-46859980
Arcsin Templates: http://templates.arcsin.se/grunge-superstar-website-template/
Python: http://python.org
PIL for image processing and matplotlib for graphing.
wxPython for the GUI
Stani's Python Editor: http://pythonide.blogspot.com
Ubuntu Forums: http://ubuntuforums.org/forumdisplay.php?f=39
Dive into Python: http://diveintopython.org
ASPN: http://aspn.activestate.com
Bytes: http://bytes.com
ASCII art generator: http://www.network-science.de/ascii
Tango  Icon Library for some icons: http://tango.freedesktop.org"""

import os,sys

# Import default config in case of failure to import user configuration
try:
    from default_config import *
    default = True
except ImportError:
    default = False
try:
    from config import *
    
except ImportError:
    print "config.py not found.",
    if default:
        print  "Using default configuration."
    else:
        print "Default Configuration not found! Attempting to crash and burn nicely.\nPlease download http://tremcs.googlecode.com/svn-history/r%s/trunk/default_config.py and place it in the tremcs directory."%(__version__)
        sys.exit()
"""Initialise config"""
    
# Location of the tremcs folder (where this file is)
tremcs_dir = sys.path[0] + "/"

# Try to get name from autogen.cfg
try:
    autogen = open(trem_dir + "/autogen.cfg",'r').readlines()
except IOError:
    autogen = ""
    
if name == "":
    for line in autogen:
        if "seta name" in line:
            name = line.split(' ')[2].replace("'","").replace('"','').replace('\n','')

    
# Check if ^7 is at end of name and remove ^colours from name
if name[-2:] == "^7":
    pass
else:
    name = name + "^7"

try: 
    rendered_name
    name_error = False
except NameError:
    name_error = True
    
if rendered_name == "" or name_error:
    rendered_name = name
    for colour in colours:
        rendered_name = rendered_name.replace("^" + colour,"")

# Print name if --name flag is used
if "--name" in sys.argv:
    print "Detected name: ", name
    print "Rendered as:   ", rendered_name
    
# Get all the variables and append the tremcs_dir and trem_dir locations to them.
variables = ['theme', 'dumpfilename', 'statsfilename', 'quickstatsfilename', 'graphdatafilename', 'livedatafilename', 
'lockfile', 'avatar_save', 'banner_save', 'userbar_image_save', 'userbar_anim_save', 'image_folder', 
'htmlpage_template', 'htmlpage_output', 'graph_all','graph_live', 'graph_allkills', 'graph_alldeaths', 'graph_kills', 
'graph_deaths', 'graph_ratio', 'graph_allratio','graph_piekills','graph_piedeaths']

for variable in variables:
    vars()[variable] = tremcs_dir + vars()[variable]
    
variables = ['currentteamfile','opponentteamfile','currentteamfilesay','opponentteamfilesay','allteamsfile','yourstatsfile', 'playerstatsfile','playerstatsfilesay']

for variable in variables:
    vars()[variable] = trem_dir + vars()[variable]


# Warn about errors?
warn = True
# Complain about no killdump?
save_stats = False
# Are all kills being counted or just during one game?
gamekills_only = False

## Get old stats first.
try:
    execfile(quickstatsfilename)
except IOError:
    if warn:
        print "Quick Stats file not found. Please check %s."%(quickstatsfilename)
    deathstats_old = {'tyrant_maul': 0, 'dretch': 0, 'granger': 0, 'tesla': 0, 'tyrant_trample': 0, 'goon_pounce': 0, 'saw': 0, 'reactor': 0, 'pulserifle': 0, 'turret': 0, 'irradiated': 0, 'acid': 0,'tube': 0, 'lasgun': 0, 'poison': 0, 'mara_claw': 0, 'lucifer': 0, 'flamethrower': 0, 'explosion': 0, 'blaster': 0, 'lisk_swipe': 0, 'goon_snipe': 0, 'massdriver': 0, 'fell': 0, 'lisk_gas': 0, 'rifle': 0, 'mara_zap': 0, 'chaingun': 0, 'died': 0, 'om': 0, 'shotgun': 0, 'hive': 0, 'goon_chomp': 0, 'grenade': 0,'toasted':0,'blew':0,'teamkill':0 }
    killstats_old = {'tyrant_maul': 0, 'dretch': 0,  'granger': 0,'tyrant_trample': 0, 'goon_pounce': 0, 'saw': 0, 'pulserifle': 0, 'lasgun': 0, 'poison': 0, 'mara_claw': 0, 'lucifer': 0, 'flamethrower': 0, 'blaster': 0, 'goon_snipe': 0, 'massdriver': 0, 'lisk_gas': 0, 'rifle': 0, 'mara_zap': 0, 'chaingun': 0, 'shotgun': 0, 'lisk_swipe': 0, 'goon_chomp': 0, 'grenade': 0,'teamkill':0}

## Theme Support

# First import DefaultTheme in case of failure to import user theme
try:
    Theme = __import__('DefaultTheme')
    import_success = True
except ImportError:
    if warn:
        print "DefaultTheme not found! You will not be able to use any image features.\n Please get DefaultTheme from the TremCS website."
if theme == "":
    if warn:
        print "No theme loaded, using default."
else:
    try:
        Theme = __import__(theme.split('/')[-1])
        import_success = True
    except (ImportError,ValueError):
        if warn:
            print "Theme loading failed, Using default."

    
#### Start classes ####

class InputOutput:
    """Input and Output functions"""
    def OpenDumpFile(self,read=1):
        
        """Open dumpfile to get stats.
        If read is 1, dumpfile is returned as a string
        if read is 2, dumpfile is returned as a list of lines"""
    
        try:
            dumpfile = open(dumpfilename, 'r')
            if read == 1:
                dumpfile = dumpfile.read()
            elif read == 2:
                dumpfile = dumpfile.readlines()
        except IOError:
            if warn:
                if save_stats == False:
                    print "Dump file not found. Please check %s. Using blank file."%(dumpfilename)
            dumpfile = ""
        return dumpfile

    
    def WriteQuickStats(self,destroy=True):
        """Append short stats to file.
        If destroy is True, dump file is removed"""
        quick_file = open(quickstatsfilename, 'w')
        killstats = StatsFunctions().AllTimeKills()
        deathstats = StatsFunctions().AllTimeDeaths()
        print >> quick_file, 'deathstats_old = %s\nkillstats_old = %s'%(str(deathstats),str(killstats))
        # Remove Dump File!!!
        if destroy:
            try:
                os.remove(dumpfilename)
            except OSError:
                print "Failed to remove ",dumpfilename + "."
                
    
    def ExportToStats(self,destroy_dump=False,relevant_only=True):
        """Exports raw log file to a master dump file.
        If destroy_dump is True, then raw log file will be deleted.
        If relevant_only is True, then only lines with player name are saved."""
        dump = self.OpenDumpFile(2)

        # Open Stats file for appending
        stats_file = open(statsfilename, 'a')
        if dump == "":
            pass
        else:
            try:
                import time,datetime
                print >> stats_file, "\n<|### New Log Start - %s - %s ###|>\n"%(time.strftime("%a, %d %b %Y"),datetime.datetime.now())
                if relevant_only: # If only relevant lines are collected, find lines with [name] and print to file
                    for line in dump:
                        if name in line:
                            line = line.replace(name,'[name]')
                            print >> stats_file, line,
                else: # Otherwise print everything to file
                    for line in dump:
                        line = line.replace(name,'[name]')
                        print >> stats_file,line,
                stats_file.close()
            except IOError:
                if warn:
                    print "Stats file not found. Please check %s."%(statsfilename)
                sys.exit()
            # Remove Dump File!!!
            if destroy_dump:
                try: os.remove(dumpfilename)
                except OSError:
                    print "Failed to remove ",dumpfilename,"."
                
    
    def SaveGraphData(self):
        """Save data for long term graph"""
        import datetime
        graph_data = open(graphdatafilename, 'a')
        # Separate games in session
        separate_games = InputOutput().OpenDumpFile().split('%s entered the game'%name)
        for game in separate_games[1:]:
            if StatsFunctions().TotalKills(game) == 0:
                pass
            else:
                print >> graph_data, "%s/%s/%s/%s/%s/%s/%s"%(datetime.datetime.now(),StatsFunctions().TotalKills(game), StatsFunctions().TotalDeaths(game),StatsFunctions().Ratio(game), StatsFunctions().AllTimeTotalKills(),StatsFunctions().AllTimeTotalDeaths(),StatsFunctions().AllTimeRatio())

    
    def SaveLiveData(self,interval=30):
        """Save graph data during gameplay
        Interval is the time to sleep after each loop"""
        import datetime, time
        try:
            os.remove(livedatafilename)
        except:
            "none"
        live_data = open(livedatafilename, 'w')
        live_data.close()
        currenttime = -0.5
        while InputOutput().FileExists(lockfile):
            currenttime = currenttime + float(interval)/60
            live_data = open(livedatafilename, 'a')
            print >> live_data, "%s/%s/%s/%s"%(currenttime,StatsFunctions().TotalKills(),StatsFunctions().TotalDeaths(),StatsFunctions().Ratio())
            live_data.close()
            time.sleep(interval)
            
    
    def FileExists(self,f):
        """Check if a file exists, where f is the file"""
        try:
            file = open(f)
        except IOError:
            return False
        else:
            return True


class Networking:
    """Networking and file manipulation functions"""    
    
    def UploadViaFTP(self,object,status=3):
        """Upload file to server or copy to local directory
        The object is the tuple (source, destination_relative_to_ftpdir)
        If the status is 0, an open ftp connection is closed after upload
        If the status is 1, the ftp connection is first opened, then file is uploaded
        If the status is 2, an already open connection is used
        If the status is 3, the ftp connection is opened, file is uploaded and then closed"""
        
        
        if local_upload:
            import shutil
            objectloc,filename = object 
            shutil.move(objectloc, ftpdir + "/" + filename)
        else:
            import ftplib
            global server # Make server a global variable
            if status == 1: # If connection needs to be opened before file is uploaded
                server = ftplib.FTP(ftpserver,ftpuser,ftppass)
                server.cwd(ftpdir)
                filename,objectloc = object
                file = open(filename,'rb')
                server.storbinary('STOR %s'%(objectloc), file)
                file.close()
            elif status == 0: # If connection needs to be closed after file is uploaded
                filename,objectloc = object
                file = open(filename,'rb')
                server.storbinary('STOR %s'%(objectloc), file)
                file.close()
                server.quit()
            elif status == 2: # If connection is open and doesn't need to be closed
                filename,objectloc = object
                file = open(filename,'rb')
                server.storbinary('STOR %s'%(objectloc), file)
                file.close()
            elif status == 3: # If you only need to transfer a single file
                server = ftplib.FTP(ftpserver,ftpuser,ftppass)
                server.cwd(ftpdir)
                filename,objectloc = object
                file = open(filename,'rb')
                server.storbinary('STOR %s'%(objectloc), file)
                file.close()
                server.close()
        print "%s uploaded!"%objectloc
    
    def UploadWebPage(self,avatargloss=True,bannergloss=True,userbargloss=True):
        """Create a web stats page and then uploads it along with the dependent objects
        Set avatargloss, bannergloss and userbargloss to True if you want a foreground"""
        # First create and upload webpage
        self.UploadViaFTP(Creators().WebPage(bannergloss,avatargloss,userbargloss, alone=True),1)
        # Then create and upload everything else
        template_original = open(htmlpage_template, 'r').read()
        # due to annoying bug, double quotes must be used within Graph()
        extras = {'[graph_all]':'Creators().Graph("all")','[graph_allkills]':'Creators().Graph("allkills")','[graph_alldeaths]':'Creators().Graph("alldeaths")','[graph_kills]':'Creators().Graph("kills")','[graph_deaths]':'Creators().Graph("deaths")','[graph_ratio]':'Creators().Graph("ratio")','[graph_allratio]':'Creators().Graph("allratio")','[graph_live]':'Creators().Graph("live")','[graph_piekills]':'Creators().Graph("piekills")','[graph_piedeaths]':'Creators().Graph("piedeaths")','[banner_image':'Creators().Banner(bannergloss)','[avatar_image]':'Creators().Avatar(avatargloss)','[userbar_image]':'Creators().Userbar(userbargloss)','[graph_piekills]':'Creators().Graph("piekills")','[graph_piedeaths]':'Creators().Graph("piedeaths")'}
        number = 0
        total = 0
        extras_create = [] # list of objects to create and upload
        for item in extras:
            if item in template_original:
                if "graph" in item and "live" not in item and "pie" not in item: # live graph doesn't reuse variables
                    if number == 0:
                        extras_create.append("self.UploadViaFTP(%s,[pos])"%extras[item].replace('")','",status=0)'))
                        number = 1
                    else:
                        extras_create.append("self.UploadViaFTP(%s,[pos])"%extras[item].replace('")','",status=1)'))
                else:
                    extras_create.append("self.UploadViaFTP(%s,[pos])"%extras[item])
                total += 1
        created = 0
        for item in extras_create:
            if created < total:
                exec(item.replace('[pos]',"2"))
            else:
                exec(item.replace('[pos]',"0"))
        
        


class HelperFunctions:
    """Extra functions to simplify methods"""
    
    def AddDicts(self,dict1, dict2):
        """Add two dictionaries together if the keys are the same
        dict1 and dict2 are the two dictionaries"""
        dict_total = {}
        for keys in dict2:
            dict_total["%s"%(keys)] = dict1["%s"%(keys)] + dict2["%s"%(keys)]
        return dict_total

    
    def SortDict(self,dict):
        """Sort dictionary by values in descending order and returns tuples in a list
        dict is the dictionary to be sorted"""
        from operator import itemgetter
        return sorted(dict.iteritems(), key=itemgetter(1), reverse=True)
    
    
    def DictSum(self,dict):
        """Retuns sum of key values in dictionary or list
        dict is the dictionary/list to be summed"""
        total = 0
        if type(dict) == type({}):
            try:
                for item in dict:
                    total += dict[item]
                return total
            except TypeError:
                print "Dictionary values aren't all integers or decimals!"
        elif type(dict) == type([]):
            try:
                for item in dict:
                    total += item
                return total
            except TypeError:
                print "List values aren't all integers or decimals!"
    
    def ColourText(self,text,type="pil"):
        """Convert Quake colour codes to HTML or PIL colours
        If type is html, <span> tags are returned as a string
        If type is pil, tuples (string,colour) in a list are returned
        """
        if type == "html":
            for colour in colours:
                colour_extra = "^" + colour
                if colour_extra in text:
                    text = text + "</span>"
                text = text.replace(colour_extra,'<span style="color: %s;">'%(colours[colour]))
            return text
        if type == "pil":
            coloured_text = [] # list of tuples of (word,colour)
            if text[1] <> "7":
                text = "^7" + text # Makes plain text white
            
            text = text.split('^')
            text.remove('')
            for item in text:
                for colour in colours:
                    if item[0] == colour:
                        coloured_text.append((item[1:],colours[colour]))
            
            return coloured_text
        
    
    def RemoveColour(self,string):
        """Remove quake colours from string"""
        for colour in colours:
            string = string.replace("^" + colour,'')
        return string
    
    
    def ReplaceValues(self,string,type="def"):
        """Replace items in a string with actual values.
        Set string to 'help' for a list of placeholders.
        Set type to 'ub' to delete [name]."""
        lastline = open(graphdatafilename, 'r').readlines()[-1].split('/')
        if coloured_name:
            special_name = self.ColourText(name,"html")
        else:
            special_name = rendered_name
        import time
        values = {  '[name]': special_name,'[_name]':rendered_name,'[date]':time.strftime("%a, %d %b %Y"),'[kills]': lastline[1],'[deaths]': lastline[2],'[ratio]': lastline[3],'[alltimekills]': StatsFunctions().AllTimeTotalKills(),'[alltimedeaths]': StatsFunctions().AllTimeTotalDeaths(),'[alltimeratio]':StatsFunctions().AllTimeRatio(),'[favweapon]':StatsFunctions().FavWeapon()[1],'[leastfavweapon]':StatsFunctions().FavWeapon(False)[1],'[quote_short]':StatsFunctions().FavQuote(max_length=max_length_short,min_length=min_length_short,nofail=True),'[quote]':StatsFunctions().FavQuote(min_length=min_length,max_length=max_length,nofail=True),
                    '[human]': StatsFunctions().AllTimeTotalKills('h'),'[human_ratio]':StatsFunctions().AllTimeRatio('h'),'[blaster]': StatsFunctions().AllTimeKills()["blaster"], '[rifle]': StatsFunctions().AllTimeKills()["rifle"], '[saw]': StatsFunctions().AllTimeKills()["saw"], '[shotgun]': StatsFunctions().AllTimeKills()["shotgun"], '[chaingun]': StatsFunctions().AllTimeKills()["chaingun"], '[flamethrower]': StatsFunctions().AllTimeKills()["flamethrower"], '[lasgun]': StatsFunctions().AllTimeKills()["lasgun"], '[massdriver]': StatsFunctions().AllTimeKills()["massdriver"], '[pulserifle]': StatsFunctions().AllTimeKills()["pulserifle"], '[lucifer]': StatsFunctions().AllTimeKills()["lucifer"], '[grenade]': StatsFunctions().AllTimeKills()["grenade"],
                    '[alien]' : StatsFunctions().AllTimeTotalKills('a'), '[alien_ratio]':StatsFunctions().AllTimeRatio('a'),'[dretch]': StatsFunctions().AllTimeKills()["dretch"], '[lisk_swipe]': StatsFunctions().AllTimeKills()["lisk_swipe"], '[lisk_gas]': StatsFunctions().AllTimeKills()["lisk_gas"], '[mara_claw]': StatsFunctions().AllTimeKills()["mara_claw"], '[mara_zap]': StatsFunctions().AllTimeKills()["mara_zap"], '[goon_chomp]': StatsFunctions().AllTimeKills()["goon_chomp"], '[goon_pounce]': StatsFunctions().AllTimeKills()["goon_pounce"], '[goon_snipe]': StatsFunctions().AllTimeKills()["goon_snipe"], '[tyrant_maul]': StatsFunctions().AllTimeKills()["tyrant_maul"], '[tyrant_trample]': StatsFunctions().AllTimeKills()["tyrant_trample"], '[granger]': StatsFunctions().AllTimeKills()["granger"], '[poison]': StatsFunctions().AllTimeKills()["poison"],
                    '[human_deaths]': StatsFunctions().AllTimeTotalDeaths('h'),'[blaster_deaths]': StatsFunctions().AllTimeDeaths()["blaster"], '[rifle_deaths]': StatsFunctions().AllTimeDeaths()["rifle"], '[saw_deaths]': StatsFunctions().AllTimeDeaths()["saw"], '[shotgun_deaths]': StatsFunctions().AllTimeDeaths()["shotgun"], '[chaingun_deaths]': StatsFunctions().AllTimeDeaths()["chaingun"], '[flamethrower_deaths]': StatsFunctions().AllTimeDeaths()["flamethrower"], '[lasgun_deaths]': StatsFunctions().AllTimeDeaths()["lasgun"], '[massdriver_deaths]': StatsFunctions().AllTimeDeaths()["massdriver"], '[pulserifle_deaths]': StatsFunctions().AllTimeDeaths()["pulserifle"], '[lucifer_deaths]': StatsFunctions().AllTimeDeaths()["lucifer"], '[grenade_deaths]': StatsFunctions().AllTimeDeaths()["grenade"],
                    '[alien_deaths]' : StatsFunctions().AllTimeTotalDeaths('a'), '[dretch_deaths]': StatsFunctions().AllTimeDeaths()["dretch"], '[lisk_swipe_deaths]': StatsFunctions().AllTimeDeaths()["lisk_swipe"], '[lisk_gas_deaths]': StatsFunctions().AllTimeDeaths()["lisk_gas"], '[mara_claw_deaths]': StatsFunctions().AllTimeDeaths()["mara_claw"], '[mara_zap_deaths]': StatsFunctions().AllTimeDeaths()["mara_zap"], '[goon_chomp_deaths]': StatsFunctions().AllTimeDeaths()["goon_chomp"], '[goon_pounce_deaths]': StatsFunctions().AllTimeDeaths()["goon_pounce"], '[goon_snipe_deaths]': StatsFunctions().AllTimeDeaths()["goon_snipe"], '[tyrant_maul_deaths]': StatsFunctions().AllTimeDeaths()["tyrant_maul"], '[tyrant_trample_deaths]': StatsFunctions().AllTimeDeaths()["tyrant_trample"], '[granger_deaths]': StatsFunctions().AllTimeDeaths()["granger"], '[poison_deaths]': StatsFunctions().AllTimeDeaths()["poison"],
                    '[turret]': StatsFunctions().AllTimeDeaths()["turret"], '[tesla]': StatsFunctions().AllTimeDeaths()["tesla"], '[explosion]': StatsFunctions().AllTimeDeaths()["explosion"], '[reactor]': StatsFunctions().AllTimeDeaths()["reactor"], '[gravity]': StatsFunctions().AllTimeDeaths()["fell"], '[tube]': StatsFunctions().AllTimeDeaths()["tube"], '[hive]': StatsFunctions().AllTimeDeaths()["hive"], '[acid]': StatsFunctions().AllTimeDeaths()["acid"], '[died]': StatsFunctions().AllTimeDeaths()["died"] + StatsFunctions().AllTimeDeaths()["irradiated"] + StatsFunctions().AllTimeDeaths()["blew"] + StatsFunctions().AllTimeDeaths()["toasted"],'[overmind]': StatsFunctions().AllTimeDeaths()["om"]
                        }
       
        if string == "help":
            for value in values:
                print value,values[value]
        else:
            if type == "ub": # If for a userbar, delete [name]
                if "[name]" in string:
                    string = string.replace("[name]","")
            for value in values:
                string = string.replace(value,str(values[value]))
            return string

    def TeamDicts(self,input,team="n"):
        """If input is a dictionary,dictionary of only one team is returned.
        If input is a string, it is converted to it's human name and returned with it's team
        Use team=a/h/n,
        where a is for alien dictionary
              h is for human dictionary
              n is for combined dictionary"""
        new_dict = {}
        weapons_dict = StatsFunctions.weapons_dict # Use weapons definitions
        if isinstance(input,str):
            try:
                return weapons_dict[input]
            except IndexError:
                print "No key found with name %s."%input
                
        elif isinstance(input,type({})):
            for item in input: # Check what team each weapon is from
                if weapons_dict[item][1] == team:
                    new_dict[item] = input[item]
        
            return new_dict

class InGameFunctions:
    """Functions used when playing the game"""
    
    def GetTeam(self,spec=False):
        """Return current team as humans or aliens."""
        teams = []
        string = "%s joined the "%name
        string2 = "%s abandoned"%name
        string3 = "%s onto the"%name
        while InputOutput().FileExists(lockfile):
            error = True
            while error == True:
                try:
                    for line in InputOutput().OpenDumpFile(0):
                        if string in line or string2 in line:
                            teams.append(line)
                        elif string3 in line:
                            teams.append(line.split(' ')[-2])
                    return teams[-1].split(' ')[-1].replace('\n','')
                    error = False
                except IndexError:
                    error = True
                if InputOutput().FileExists(lockfile) == False:
                    error = False
                
    
    def CurrentServer(self,allservers=False):
        """Return server that the player is currently on."""
        ipaddr = []
        for line in InputOutput().OpenDumpFile(2):
                    if "resolved" in line:
                        ipaddr.append(line.split(' ')[-1].replace('\n',''))
        try: 
            if allservers:
                return ipaddr
            else:
                return ipaddr[-1]
        except: return "Error"
        
    
    def OtherPlayers(self,part_name,first_time=True):
        """Get the players currently playing in the game or server.
    If first option is not True, player name will be matched.
    qstat will be used if possible."""
        part_name = part_name.lower()
        if quakestat_path == "" or first_time == False:
            names = []
            for line in OpenDumpFile(2):
                if "entered the game" in line:
                    names.append(line.split(' ')[:-3])
                if "disconnected" in line:
                    names.remove(line.split(' ')[:-1])
            names.sort()
            last = names[-1]
            for i in range(len(names)-2, -1, -1):
                if last==names[i]: del names[i]
                else: last=names[i]

            coloured_names = []

            for item in names:
                name = ""
                for part in item:
                    if len(item) > 1:
                        name = name + part + " "
                    else:
                        name = part
                if name[-1] == " ":
                    name = name[:-1]
                coloured_names.append(name)
            
        elif quakestat_path <> "" or first_time:
            error = True
            while error:
                try:
                    server = self.CurrentServer()
                    if server == "Error":
                        if InputOutput().FileExists(lockfile):
                            error = True
                        else:
                            sys.exit()
                    else:
                        correct_names = os.popen('%s -carets -P  -tremulous %s -raw "\t"'%(quakestat_path,server)).read().split('\n')[1:]
                        error = False
                except IndexError:
                    print "The game server could not be found. Waiting..."
                    import time
                    time.sleep(0.5)
                    error = True
            coloured_names = []
            for line in correct_names:
                if line.split('\t')[0] == "":
                    pass
                else:
                    coloured_names.append(line.split('\t')[0])

        names = {}
        for item in coloured_names:
            name = item
            for colour in colours:
                name_lower = name.replace("^" + colour,"").lower()
                name = name.replace("^" + colour,"")
            # Causes bugs...
            #
            #if item[-2:] == "^7":
            #    names[(name,name_lower)] = item
            #else:
            #    names[(name,name_lower)] = item + "^7"
            names[(name,name_lower)] = item + "^7"
        if part_name == "1":
            return names
        else:
            for item in names:
                if part_name in item[1]:
                    return names[item],item

    
    def TeamStats(self,team="n"): 
        """Stats for a team during a game.
        Use team=a/h/n for different team stats,
        where h is for human team stats
              a is for alien team stats
              n is for both kill stats
        Stats are returned as a tuple: (kill, deaths)"""
        
        statsfile = InputOutput().OpenDumpFile().split('%s joined the'%name)[-1]
        alienkillstats = {}
        humankillstats = {}
        killstats = {}
        deathstats = {}
        aliendeathstats = {}
        humandeathstats = {}
        
        aliens = {'dretch':'bitten by ','lisk_swipe':'swiped by ','lisk_gas':'gassed by ','mara_claw':'clawed by ','mara_zap':'zapped by ','goon_chomp':'chomped by ','goon_snipe':'sniped by ','goon_pounce':'pounced upon by ','tyrant_maul':'mauled by ','tyrant_trample':'way of ','poison':'against ','granger':"should leave 's buildings alone"}
        for item in aliens:
            alienkillstats[item] = statsfile.count(aliens[item])
        humans = {'blaster':'blasted by ','rifle':'machinegunned by ','saw':'sawn by ','shotgun':'gunned down by ','lasgun':'lasgunned by ','massdriver':'mass driven by ','chaingun':'chaingunned by ','pulserifle':'pulse rifled by ','flamethrower':'grilled by ','lucifer':'full force of ','grenade':"couldn't escape "}
        for item in humans:
            humankillstats[item] = statsfile.count(humans[item])
        humankillstats["shotgun"] = humankillstats["shotgun"] - statsfile.count(' was gunned down by a turret')
        humankillstats["flamethrower"] = humankillstats["flamethrower"] + statsfile.count('toasted by ')
        humankillstats["lucifer"] = humankillstats["lucifer"] + statsfile.count('fallout of ')
        
        
        if team == "a":
            return (alienkillstats, humankillstats)
        elif team == "h":
            return (humankillstats, alienkillstats)
        else:
            return (humankillstats,alienkillstats)

    
    def GetPlayer(self,interval=1):
        """Get stats for a player based on 'Unknown command [name]'"""
        while InputOutput().FileExists(lockfile):
            first_time = True
            dump = InputOutput().OpenDumpFile(2)
            names = [rendered_name] # Use personal name for original stats to prevent crash
            for line in dump:
                if "Unknown " in line:
                    part_name = line.split(' ')[-1].replace('\n','')
                    names.append(part_name)
            
            try: 
                global name
                name =  self.OtherPlayers(names[-1],first_time)[0]
            except (TypeError,IndexError):
                pass

            playerstats = open(playerstatsfile,'w')
            playerstats_say = open(playerstatsfilesay,'w')
            print >> playerstats, """echo ^4[^7%s^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s"""%(name,str(StatsFunctions().GameKills()),str(StatsFunctions().GameDeaths()),str(StatsFunctions().GameRatio()))
            print >> playerstats_say, """say ^4[^7%s^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s"""%(name,str(StatsFunctions().GameKills()),str(StatsFunctions().GameDeaths()),str(StatsFunctions().GameRatio()))
            if quakestat_path == "": # If quakestat is not to be used, pass
                pass
            else: # Otherwise, only use quakestat on the first lookup
                first_time = False
            import time
            time.sleep(interval) # sleep for [interval] seconds

    
    def AllPlayers(self,sort="ratio"):
        """Prints stats for every player in the form [name]: [kills] [deaths] [ratio]"""
        
        players = self.OtherPlayers('1')
        player_keys = []
        player_kills = {}
        
        sort_types = {'ratio':'GameRatio()','kills':'GameKills()','deaths':'GameDeaths()','sratio':'Ratio()','skills':'TotalKills()','sdeaths':'TotalDeaths()','rank':'GameRank()'}
        for item in sort_types:
            if sort == item:
                sortby = sort_types[item]
        # Make a list out of uncoloured player names
        global name
        for item in players:
            player_keys.append(item[0])
            name = players[item]
            exec("player_kills[(players[item],item[0])] = StatsFunctions()." + sortby)
        # Sort players by kills
        players = HelperFunctions().SortDict(player_kills)
        # For all players, set name to the full player name and print stats
        
        for item in players:
            name = item[0][0]
            # Print in columns
            if sort == "rank":
                print item[0][1].ljust(max(map(len, player_keys))) + "%2s %5s %9s %13s" %(StatsFunctions().GameKills(), StatsFunctions().GameDeaths(), StatsFunctions().GameRatio(),StatsFunctions().GameRank())
            else: # Miss out rank column
                print item[0][1].ljust(max(map(len, player_keys))) + "%2s %5s %9s" %(StatsFunctions().GameKills(), StatsFunctions().GameDeaths(), StatsFunctions().GameRatio())
            

    
    def OutputTeamStats(self,interval=5):
        """Get stats for both teams and output it to a cfg file"""
        import time
        fullteam = "Our"
        fullenemy = "Enemy"
        while InputOutput().FileExists(lockfile):
            if self.GetTeam() in ("aliens","aliens."):
                team = "a"
                enemy = "h"
            elif self.GetTeam() in ("humans", "humans."):
                team = "h"
                enemy = "a"
            else:
                team = "h"
                enemy = "a"
                fullteam = "Human"
                fullenemy = "Alien"
            teamkills = 0
            enemykills = 0
            for item in self.TeamStats(team)[0]:
                teamkills = self.TeamStats(team)[0][item] + teamkills
            for item in self.TeamStats(enemy)[0]:
                enemykills = self.TeamStats(enemy)[0][item] + enemykills
            teamdeaths = 0
            enemydeaths = 0
            for item in self.TeamStats(team)[1]:
                teamdeaths = self.TeamStats(team)[1][item] + teamdeaths
            for item in self.TeamStats(enemy)[1]:
                enemydeaths = self.TeamStats(enemy)[1][item] + enemydeaths
            if teamdeaths == 0:
                teamratio = "%.3f"%teamkills
            else:
                teamratio = "%.3f" % (teamkills / teamdeaths)
            if enemydeaths == 0:
                enemyratio = "%.3f"%enemykills
            else:
                enemyratio = "%.3f" % (enemykills / enemydeaths)
            currentteam = open(currentteamfile, 'w')
            currentteamsay = open(currentteamfilesay, 'w')
            opponentteam = open(opponentteamfile, 'w')
            opponentteamsay = open(opponentteamfilesay, 'w')
            yourstats = open(yourstatsfile, 'w')
            print >> currentteam, """echo ^4[^3%s Team Stats^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s
            """%(fullteam,teamkills,teamdeaths,teamratio)
            print >> currentteamsay, """say_team ^4[^3%s Team Stats^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s"""%(fullteam,teamkills,teamdeaths,teamratio)
            print >> opponentteam, """echo ^4[^3%s Team Stats^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s"""%(fullenemy,enemykills,enemydeaths,enemyratio)
            print >> opponentteamsay, """say_team ^4[^3%s Team Stats^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s"""%(fullenemy,enemykills,enemydeaths,enemyratio)
            print >> yourstats, """echo ^4[^3Your Stats^4] ^5: ^3%s ^5Kills ^1 - ^3%s ^5Deaths^1 - ^5Ratio - ^3%s"""%(StatsFunctions().GameKills(),StatsFunctions().GameDeaths(),StatsFunctions().GameRatio())
            time.sleep(interval)
            
    
    def RunCommand(self,input,output,interval,debug=False):
        
        """Run a command based on input inside the game"""
        import time
        past_output_strings = {}
        while InputOutput().FileExists(lockfile):
            # input is in the form of a list [lookup_type,lookup_string] where lookup_string is left empty with lookup_type="default"
            dump = InputOutput().OpenDumpFile(2)
            matches = []
            # output is in the form of a dictionary. {'word to detect':'command','word2 to detect':'command2'}
            if input[0] == "default":
                lookup_string = "Unknown command "
                if len(input) == 2:
                    if debug:
                        print "Second item in list is ignored for default lookup type. Use custom lookup type if you want to use a custom lookup string."
            elif input[0] == "custom":
                try:
                    lookup_string = input[1]
                    print input[1]
                except IndexError:
                    raise IndexError, "Second part of the input list %s needs to be the lookup string."%(input)
            else:
                raise IndexError, "Input must be a list of ['default'] or ['custom','lookup_string']."
            for line in dump:
                if lookup_string in line:
                    part_input = line.split(' ')[-1].replace('\n','') # Use last part of matched line as match
                    matches.append(part_input)
            
            for item in output: # If the string matches one of the keys, set the command to the key value
                
                try:
                    if item == matches[-1]:
                        output_string = output[item]
                        matched_key = item
                except IndexError: pass
            
            try: # Prevents crashing from empty matches
                total = 0
                for item in matches:
                    if item == matched_key:
                        total += 1
                    
                try: past = past_output_strings[output_string]
                except:
                    past = 0
                if past < total:
                    import commands
                    commands.getoutput(output_string)
                    try: past_output_strings[output_string] += 1
                    except KeyError: past_output_strings[output_string] = 1
                
            except: pass
            time.sleep(interval)
            
    
    def OnEvent(self,input,output,interval):
        """Prints a modified string based on in game input"""
        import time
        while InputOutput().FileExists(lockfile):
            # input is in the form of a tuple (lookup_type,lookup_string) where lookup_string is left empty with lookup_type="default"
            dump = InputOutput().OpenDumpFile(2)
            matches = []
            # output is in the form of a dictionary. {'ot':'either print or file','s':"splitter_string",'r':{'postion':'[replacement]',etc},'os':"string with replacement values",'of':'file location'}
            # This is what's used to separate the matched text for value replacement
            try:
                splitter = output['s']
                split = True
            except KeyError:
                split = False
            # output_type is one of print, file. Print displays the text in the terminal, file prints to a file
            output_type = output['ot']
            
            # This is the string to be output along with replacements.
            output_string = output['os']
            # This is an item where the format depends on output_type. If split string,{1:'[first]',2:'[second]'} and if unsplit string, 'place_holder'
            replacements = output['r']
            # If the output_type is file, then a file needs to be specified
            if output_type == "file":
                output_file = output['of']
            
            # If the lookup_type is default, use the "Unknown Command" lookup string
            if input == "default":
                lookup_string = "Unknown command "
            # If it is a custom string, use the second string in the tuple as the lookup string
            elif input[0] == "custom":
                try:
                    lookup_string = input[1]
                except IndexError:
                    print "OnEvent() needs the second item in the input tuple to be the lookup string"
            else:
                print "input must be one of 'default','custom'"
            for line in dump:
                if lookup_string in line:
                    if input == "default":
                        part_input = line.split(' ')[-1].replace('\n','') # Use last part of matched line as match
                    else:
                        part_input = line.replace('\n','')
                    matches.append(part_input)
            
            # Check that matches are correct
            if split:
                try:
                    match = matches[-1].split(splitter)[max(replacements.keys())] # If biggest key in replacements is present in matched string, then match is correct
                    correct = True
                except IndexError:
                    correct = False
            else:
                correct = True
            
            if correct:
                try: # Prevents crashing from empty matches list
                    # Now, replace the placeholder text in output_string with actual values
                    # If this is a split string, placeholder text depends on the position of the text
                    if split:
                        for item in replacements:
                            output_string = output_string.replace(replacements[item],matches[-1].split(splitter)[item])
                    else: # If it is not a split string, placeholder text is replaced with actual value
                        output_string = output_string.replace(replacements,matches[-1])
                    
                    # Finally, this needs to be printed
                    if output_type == "file":
                        file = open(output_file,'w')
                        print >> file,output_string
                    elif output_type == "print":
                        print output_string
                except IndexError: pass
            time.sleep(interval)

class StatsFunctions:
    """Functions to count statistics"""
    
    """Used to generate more human names
    In value, first item is human names, second is team
    n = environment
    a = aliens
    h = humans"""
    weapons_dict = {'blew': ('Grenades', 'h'), 'tyrant_maul': ("Tyrant's Claw", 'a'), 'dretch': ("Dretch's Bite", 'a'), 'tesla': ('Tesla Generators', 'h'), 'rifle': ('Rifle', 'h'), 'tyrant_trample': ("Tyrant's Trample", 'a'), 'goon_pounce': ("Dragoon's Pounce", 'a'), 'teamkill': ('Teamkilling', 'n'), 'acid': ('Acid Tubes', 'a'), 'saw': ('Painsaw', 'h'), 'reactor': ('Reactor', 'h'), 'pulserifle': ('Pulse Rifle', 'h'), 'turret': ('Turrets', 'h'), 'irradiated': ('Radiation', 'h'), 'tube': ('Acid Tubes', 'a'), 'lasgun': ('Lasgun', 'h'), 'hive': ('Hives', 'a'), 'poison': ('Poison', 'a'), 'mara_claw': ("Marauder's Claw", 'a'), 'lucifer': ("Lucifer's Cannon", 'h'), 'toasted': ('Flame Thrower', 'h'), 'flamethrower': ('Flamethrower', 'h'), 'explosion': ('Explosions', 'n'), 'blaster': ('Blaster!', 'h'), 'goon_snipe': ("Dragoon's Barb", 'a'), 'massdriver': ('Mass Driver', 'h'), 'fell': ('Gravity', 'n'), 'lisk_gas': ("Basilisks' Gas", 'a'), 'granger': ('Grangers', 'a'), 'mara_zap': ("Marauder's Zap", 'a'), 'chaingun': ('Chaingun', 'h'), 'died': ('Suicides', 'n'), 'om': ('Overmind', 'a'), 'shotgun': ('Shotgun', 'h'), 'lisk_swipe': ("Basilisk's Swipe", 'a'), 'goon_chomp': ("Dragoon's Claw", 'a'), 'grenade': ('Grenade', 'h')}
    
    def KillStats(self,input="statsfile", team="n"):
        """Get kill stats for each weapon in a dictionary.
        Use team=a/h/n for stats for each species,
        where h is for human stats
              a is for alien stats
              n is for combined kill stats"""
            
        if input == "statsfile": 
            statsfile = InputOutput().OpenDumpFile()
        else: # Used to get stats for specific sections
            statsfile = input
        alienkillstats = {}
        humankillstats = {}
        killstats = {}
        
        aliens = {'dretch':'bitten by %s'%name,'lisk_swipe':'swiped by %s'%name,'lisk_gas':'gassed by %s'%name,'mara_claw':'clawed by %s'%name,'mara_zap':'zapped by %s'%name,'goon_chomp':'chomped by %s'%name,'goon_snipe':'sniped by %s'%name,'goon_pounce':'pounced upon by %s'%name,'tyrant_maul':'mauled by %s'%name,'tyrant_trample':'way of %s'%name,'poison':'against %s'%name,'granger':"should leave %s's buildings alone"%name}
        for item in aliens:
            alienkillstats[item] = statsfile.count(aliens[item])
        humans = {'blaster':'blasted by %s'%name,'rifle':'machinegunned by %s'%name,'saw':'sawn by %s'%name,'shotgun':'gunned down by %s'%name,'lasgun':'lasgunned by %s'%name,'massdriver':'mass driven by %s'%name,'chaingun':'chaingunned by %s'%name,'pulserifle':'pulse rifled by %s'%name,'flamethrower':'grilled by %s'%name,'lucifer':'full force of %s'%name,'grenade':"couldn't escape %s"%name,'teamkill':"killed by ^1TEAMMATE^7 %s"%name}
        for item in humans:
            humankillstats[item] = statsfile.count(humans[item])
        humankillstats["flamethrower"] = humankillstats["flamethrower"] + statsfile.count('toasted by %s'%name)
        humankillstats["lucifer"] = humankillstats["lucifer"] + statsfile.count('fallout of %s' %name)
        if team == "a":
            return alienkillstats
        if team == "h":
            return humankillstats
        else:
            killstats.update(alienkillstats)
            killstats.update(humankillstats)
            return killstats
        
    
    def TotalKills(self,input="statsfile"):
        """Sum of kills from events per session"""
        
        return HelperFunctions().DictSum(StatsFunctions().KillStats(input)) - StatsFunctions().KillStats(input)['teamkill']


    
    def GameKillStats(self):
        """Count kill events by player for the last game"""
        separate_games = InputOutput().OpenDumpFile().split('%s entered the game'%name)
        return self.KillStats(separate_games[-1])

    
    def GameKills(self):
        """Sum of kills from events per game"""
        separate_games = InputOutput().OpenDumpFile().split('%s entered the game'%name)
        return StatsFunctions().TotalKills(separate_games[-1])
    
    
    def DeathStats(self,input="statsfile",team="n"):
        """Get death stats for each weapon in a dictionary.
        Use team=a/h/s/n for stats for each species,
        where h is for human stats
              a is for alien stats
              s is for environment stats
              n is for combined death stats"""
        if input == "statsfile":
            statsfile = InputOutput().OpenDumpFile()
        else:
            statsfile = input
        deathstats = {}
        aliendeathstats = {}
        humandeathstats = {}
        environdeathstats = {}
        
        # Alien Weapons
        
        alien_weapons = {'dretch':"%s was bitten"%name,'lisk_swipe':"%s was swiped"%name,'lisk_gas':"%s was gassed"%name,'mara_claw':"%s was clawed"%name,'mara_zap':"%s was zapped"%name,'goon_chomp':"%s was chomped"%name,'goon_snipe':"%s was sniped"%name,'goon_pounce':"%s was pounced upon"%name,'tyrant_maul':"%s was mauled"%name,'tyrant_trample':"%s should have gotten"%name,'poison':"%s should have used"%name,'granger':"%s should leave"%name,'acid':"%s shouldn't have trod"%name,'tube':'%s was melted'%name,'hive':'%s was hunted'%name, 'om':'%s got too close to the overmind'%name}
        for item in alien_weapons:
            humandeathstats[item] = statsfile.count(alien_weapons[item])

        humandeathstats["granger"] = humandeathstats["granger"] + statsfile.count('%s should have visited a medical station.'%name)
        # Human Weapons
        
        human_weapons = {'blaster':"%s was blasted"%name,'rifle':"%s was machinegunned"%name,'saw':"%s was sawn"%name,'shotgun':"%s was gunned down"%name,'lasgun':"%s was lasgunned"%name,'massdriver':"%s was mass driven"%name,'chaingun':"%s was chaingunned"%name,'pulserifle':"%s was pulse rifled"%name,'flamethrower':"%s was grilled"%name,'lucifer':"%s felt"%name,'grenade':"%s couldn't escape"%name,'turret':'%s was gunned down by a turret'%name,'tesla':'%s was zapped by a tesla generator'%name,'reactor':'%s got too close to the reactor'%name,'teamkill':'%s was killed by ^1TEAMMATE^7'%name}
        for item in human_weapons:
            aliendeathstats[item] = statsfile.count(human_weapons[item])
        # add extra messages
        aliendeathstats["shotgun"] = aliendeathstats["shotgun"] - statsfile.count('%s was gunned down by a turret'%name)
        aliendeathstats["flamethrower"] = aliendeathstats["flamethrower"] + statsfile.count('%s was toasted'%name)
        aliendeathstats["lucifer"] = aliendeathstats["lucifer"] + statsfile.count('%s was caught' %name)
        
        
        # Environment
        
        suicides = {'irradiated':"%s irradiated"%name,'fell':'%s fell'%name,'explosion':'%s should have ran further.'%name,'toasted':'%s toasted himself'%name,'blew':'%s blew himself up.'%name}
        for item in suicides:
            environdeathstats[item] = statsfile.count(suicides[item])
        environdeathstats["died"] = statsfile.count('%s died.'%name) + statsfile.count('%s killed itself'%name)

        if team == "a":
            return aliendeathstats
        if team == "h":
            return humandeathstats
        if team == "s":
            return environdeathstats
        else:
            deathstats.update(aliendeathstats)
            deathstats.update(humandeathstats)
            deathstats.update(environdeathstats)
            return deathstats
        
    
    def TotalDeaths(self,input="statsfile"):
        """Sum of deaths from events per session"""
        return HelperFunctions().DictSum(StatsFunctions().DeathStats(input)) - StatsFunctions().DeathStats(input)['teamkill']
    
    
    def GameDeathStats(self):
        """Count death events by player for the last game"""
        separate_games = InputOutput().OpenDumpFile().split('%s entered the game'%name)
        return DeathStats(separate_games[-1])

    
    def GameDeaths(self):
        """Sum of deaths from events per game"""
        separate_games = InputOutput().OpenDumpFile().split('%s entered the game'%name)
        return StatsFunctions().TotalDeaths(separate_games[-1])
    
    
    def Ratio(self,input="statsfile",decimals=3):
        """Divide kills by deaths per session"""
        if StatsFunctions().TotalDeaths(input) == 0:
            return "%.3f" %float(StatsFunctions().TotalKills(input))
        elif StatsFunctions().TotalKills(input) == 0:
            ratio = 0 - StatsFunctions().TotalDeaths(input)
            return "%.3f" %float(ratio)
        else:
            return "%.3f" %(StatsFunctions().TotalKills(input) / StatsFunctions().TotalDeaths(input))

    
    def GameRatio(self):
        """Divide kills by deaths per game"""
        separate_games = InputOutput().OpenDumpFile().split('%s entered the game'%name)
        return StatsFunctions().Ratio(separate_games[-1])

    
    def AllTimeDeaths(self):
        """Return *All Time* death stats as dictionary"""
        if save_stats:
            return deathstats_old
        else:
            return HelperFunctions().AddDicts(self.DeathStats(), deathstats_old)
        
        
    def AllTimeKills(self):
        """Return *All Time* death stats as dictionary"""
        if save_stats:
            return killstats_old
        else:
            return HelperFunctions().AddDicts(StatsFunctions().KillStats(), killstats_old)
        
    
    def AllTimeTotalDeaths(self,team="n"):
        """Sum of deaths.
        Use team="a/h/n" for specific team stats,
        where a is for alien deaths
              h is for human deaths
              n is for combined deaths"""
        totaldeaths = 0
        deathstats = self.AllTimeDeaths()
        if team == "n":
            for item in deathstats:
                totaldeaths = totaldeaths + deathstats[item]
        elif team == "h": # If team is humans
            totaldeaths = totaldeaths + deathstats["blaster"] + deathstats["rifle"] + deathstats["saw"] + deathstats["shotgun"] + deathstats["lasgun"] + deathstats["massdriver"] + deathstats["chaingun"] + deathstats["pulserifle"] + deathstats["flamethrower"] + deathstats["lucifer"] + deathstats["grenade"]
        elif team == "a": # If team is aliens
            totaldeaths = totaldeaths + deathstats["dretch"] + deathstats["lisk_swipe"] + deathstats["lisk_gas"] +  deathstats["mara_claw"] + deathstats["mara_zap"] + deathstats["goon_chomp"] + deathstats["goon_snipe"] + deathstats["goon_pounce"] + deathstats["tyrant_maul"] + deathstats["tyrant_trample"] + deathstats["poison"] + deathstats["granger"]
        else:
            raise ValueError('Incorrect team code! One of a/h/n')
        return totaldeaths
    
    
    def AllTimeTotalKills(self,team="n"):
        """Sum of kills
        Use team="a/h/n" for specific team stats,
        where a is for alien kills
              h is for human kills
              n is for combined kills"""
        totalkills = 0
        killstats = self.AllTimeKills()
        if team == "n":
            for item in killstats:
                totalkills = totalkills + killstats[item]
        elif team == "h": # If team is humans
            totalkills = totalkills + killstats["blaster"] + killstats["rifle"] + killstats["saw"] + killstats["shotgun"] + killstats["lasgun"] + killstats["massdriver"] + killstats["chaingun"] + killstats["pulserifle"] + killstats["flamethrower"] + killstats["lucifer"] + killstats["grenade"]
        elif team == "a": # If team is aliens
            totalkills = totalkills + killstats["dretch"] + killstats["lisk_swipe"] + killstats["lisk_gas"] + killstats["mara_claw"] +  killstats["mara_zap"] + killstats["goon_chomp"] + killstats["goon_snipe"] + killstats["goon_pounce"] + killstats["tyrant_maul"] + killstats["tyrant_trample"] + killstats["poison"] + killstats["granger"]
        else:
            raise ValueError('Incorrect team code! One of a/h/n')
        return totalkills
    
    
    def AllTimeRatio(self,team="n"):
        """Divide All time kills by deaths
        Use team="a/h/n" for specific team stats,
        where a is for alien ratio
              h is for human ratio
              n is for combined ratio"""
        if team == "n":
            if self.AllTimeTotalDeaths() == 0:
                return "%.3f" %float(self.AllTimeTotalKills())
            else:
                return "%.3f" % (self.AllTimeTotalKills() / self.AllTimeTotalDeaths())
        if team == "h":
            if self.AllTimeTotalDeaths("h") == 0:
                return "%.3f" %float(self.AllTimeTotalKills("a"))
            else:
                return "%.3f" % (self.AllTimeTotalKills("h") / self.AllTimeTotalDeaths("a"))
        if team == "a":
            if self.AllTimeTotalDeaths("a") == 0:
                return "%.3f" %float(self.AllTimeTotalKills("h"))
            else:
                return "%.3f" % (self.AllTimeTotalKills("a") / self.AllTimeTotalDeaths("h"))

    
    def FavWeapon(self,fav=True):
        """Returns most/least used weapon as a tuple (shortname,longname)
        If fav is True, the most used weapon is returned
        If fav is False,the least used weapon is returned"""
        ClassesDict = self.weapons_dict
        if fav:
            favweapon = (HelperFunctions().SortDict(StatsFunctions().AllTimeKills())[0][0],ClassesDict[HelperFunctions().SortDict(StatsFunctions().AllTimeKills())[0][0]][0])
        else:
            favweapon = (HelperFunctions().SortDict(StatsFunctions().AllTimeKills())[-1][0],ClassesDict[HelperFunctions().SortDict(StatsFunctions().AllTimeKills())[-1][0]][0])
        return favweapon

    
    def GetWeapon(self,weapon):
        """Get stats for a particular weapon
        For a list of weapons, set weapon to something random"""
        killstats = self.AllTimeKills()
        deathstats = self.AllTimeDeaths()
        if weapon not in deathstats.keys():
            print "Weapon must be one of ",
            for item in deathstats:
                print item + " ",
        for item in deathstats:
            if item == weapon:
                try:
                    print "Total Kills: ",killstats[weapon]
                except KeyError:
                    pass
                try:
                    print "Total Deaths: ",deathstats[weapon]
                except KeyError:
                    pass
            
                    
    
    def GetLiveWeapon(self,weapon):
        """Get weapon stats during game
        For a list of weapons, set weapon to something random"""
        killstats = self.KillStats()
        deathstats = self.DeathStats()
        if weapon not in deathstats.keys():
            print "Weapon must be one of ",
            for item in deathstats:
                print item + " ",
        for item in deathstats:
            if item == weapon:
                try:
                    print "Kills: ",killstats[weapon]
                except KeyError:
                    pass
                try:
                    print "Deaths: ",deathstats[weapon]
                except KeyError:
                    pass
    
    
    def GameRank(self):
        """For games, multiply kills and ratio to get rank"""
        return float(self.GameKills())*float(self.GameRatio())
        
    
    def FavQuote(self,random=True,display="top",first=0,last=25,max_length=-1,min_length=-1,nofail=False):
        """Get favourite quote from stats file
        You need to use the InputOutput().ExportToStats() function before this
        If random is True, a random quote will be selected from the list
        If display is set to "top", a quote from the list is selected
        If display is set to "list", all the quotes in the list are returned
        first and last is the range of quotes in the list
        max_length is the biggest length the quote should be
        min_length is the smallest length the quote should be
        If nofail is True, "" will be returned upon error
        If nofail is False, the function will cause the script to exit upon error"""
        
        try: file = open(statsfilename).readlines()
        except IOError:
            print "Stats file not found. Please check %s. \nSee --export-dump and --dump-all."%(statsfilename)
            if nofail:
                return ""
            else:
                sys.exit()
        
        quotes = {}
        # keywords
        keywords = ["([name])", "[^1A^7] [name]" ,"[^4H^7] [name]", "[S] [name]"]
        for line in file:
            for item in keywords:
                if item in line: # Only use text from say and say_team
                    clean_line = HelperFunctions().RemoveColour(line.replace(item + ": ",'')).replace('\n','')
                    
                    # If bigger than min and smaller than max, add to dictionary
                    if max_length == -1:
                        if min_length == -1: 
                            quotes.setdefault(clean_line, 0)
                            quotes[clean_line] += 1
                        else:
                            if len(clean_line) > min_length:
                                quotes.setdefault(clean_line, 0)
                                quotes[clean_line] += 1
                    else:
                        if len(clean_line) < max_length:
                            if min_length == -1: 
                                quotes.setdefault(clean_line, 0)
                                quotes[clean_line] += 1
                            else:
                                if len(clean_line) > min_length:
                                    quotes.setdefault(clean_line, 0)
                                    quotes[clean_line] += 1
        
        sorted = HelperFunctions().SortDict(quotes)
        if display == "top":
            if random:
                # Get random quote from top ten
                import random, string
                choice = random.choice(sorted[:last])[0]
                # Clean up the string - keep only printable characters
                choice = filter(lambda x: x in string.printable, choice)
                if "   " in choice:
                    choice = choice.split('   ')[-1]

                if choice[0] == "s":
                    choice = choice [2:]
                while choice[0] == " ":
                    choice = choice[1:]
            else:
                choice = sorted[0][0]
            
            
        elif display == "list":
            choice = ""
            for item in sorted[first:last]:
                choice = choice + str(item[1]) + " times: " + item[0] + "\n"
        return choice
        
class Creators:
    """Stats display creators"""
    
    ## Create Images
    def Avatar(self,fg=True):
        """Small 100x100 icon for avatars
        If fg is True, foreground is added to image"""
        from PIL import Image, ImageDraw, ImageFont
        # Images
        background_avatar_file = "%s/%s"%(theme,Theme.background_avatar)
        foreground_avatar_file = "%s/%s"%(theme,Theme.foreground_avatar)
    
        image = Image.open(background_avatar_file)
        foreground = Image.open(foreground_avatar_file)
        draw = ImageDraw.Draw(image)
        # Font
        font4file = "%s/%s"%(theme,Theme.font_avatar[0])
        font4size = Theme.font_avatar[1]
        font4 = ImageFont.truetype(font4file, font4size)
        font4colour = Theme.font_avatar[2]
        if gamekills_only:
            kills = StatsFunctions().TotalKills()
            deaths = StatsFunctions().TotalDeaths()
            ratio = StatsFunctions().Ratio()
        else:
            kills = StatsFunctions().AllTimeTotalKills()
            deaths = StatsFunctions().AllTimeTotalDeaths()
            ratio = StatsFunctions().AllTimeRatio()
        
        draw.text(Theme.kills_atc, "Kills: %s" %(str(kills)), font=font4, fill=font4colour)
        draw.text(Theme.deaths_atc, "Deaths: %s"%(str(deaths)), font=font4, fill=font4colour)
        draw.text(Theme.ratio_atc, "Ratio: %s"%(str(ratio)),font=font4, fill=font4colour)
        # Use image as mask for png alpha transparency
        if fg:
            image.paste(foreground,(0,0),foreground)
        image.save(avatar_save)
        print "%s created!"%(avatar_save.split('/')[-1])
        return avatar_save, ftpavatar
    
    
    def Userbar(self,fg=True,coloured_name=coloured_name):
        """Animated userbar image 350x35
        If fg is True, foreground is added to image
        If coloured_name is true, player name is coloured (default is set in config.py)"""
        from PIL import Image, ImageDraw, ImageFont
        # Images
        background_userbar_file = "%s/%s"%(theme,Theme.background_userbar)
        foreground_userbar_file = "%s/%s"%(theme,Theme.foreground_userbar)
        # Fonts
        font5file = "%s/%s"%(theme,Theme.font1_userbar[0])
        font5size = Theme.font1_userbar[1]
        font5colour = Theme.font1_userbar[2]
        font6file = "%s/%s"%(theme,Theme.font2_userbar[0])
        font6size = Theme.font2_userbar[1]
        font6colour = Theme.font2_userbar[2]
        font7file = "%s/%s"%(theme,Theme.font3_userbar[0])
        font7size = Theme.font3_userbar[1]
        font7colour = Theme.font3_userbar[2]
        font1 = ImageFont.truetype(font5file, font5size)
        font2 = ImageFont.truetype(font6file,font6size)
        font3 = ImageFont.truetype(font7file,font7size)
        frames = []
        for stats in stats_list:
            image = Image.open(background_userbar_file)
            foreground = Image.open(foreground_userbar_file)
            draw = ImageDraw.Draw(image)
            draw.text(Theme.ub_mainstats, "%s" %(HelperFunctions().ReplaceValues(stats,'ub')), font=font1, fill=font5colour)
            draw.text(Theme.ub_stats, Theme.stats_text, font=font2, fill=font6colour)
            # Draw name in colour
            if "[name]" in stats:
                if coloured_name:
                    text = HelperFunctions().ColourText(name)
                    co = Theme.ub_name
                    for item in text:
                        draw.text(co, item[0], font=font1,fill=item[1])
                        co = (co[0]+draw.textsize(item[0],font=font1)[0],co[1])
                else:
                    draw.text(Theme.ub_name,rendered_name,font=font1, fill=font7colour)
            
            if fg:
                image.paste(foreground,(0,0),foreground)
            image.save("%s/tmp%s.png"%(theme,stats_list.index(stats)))
            
            frames.append(theme + "/tmp" + str(stats_list.index(stats))+".png")
        if len(frames) == 1:
            os.rename(frames[0],userbar_image_save)
            print "%s created!"%(userbar_image_save.split('/')[-1])
            return userbar_image_save, ftpuserbar_image
        else:
            file_paths = " "
            for file in frames:
                file_paths = file_paths + file + " "
            os.popen('"%s" -delay %s -loop 0 %s %s'%(convert_path,userbar_anim_delay,file_paths,userbar_anim_save))
            for file in frames:
                os.remove(file)
            print "%s created!"%(userbar_anim_save.split('/')[-1])
            return userbar_anim_save, ftpuserbar_anim
        
    
    def Banner(self,fg=True,coloured_name=coloured_name):
        """Big Banner 420x120
        If fg is True, foreground is added to image
        If coloured_name is true, player name is coloured (default is set in config.py)"""
        from PIL import Image, ImageDraw, ImageFont
        # Images
        background_banner_file = "%s/%s"%(theme,Theme.background_banner)
        foreground_banner_file = "%s/%s"%(theme,Theme.foreground_banner)
        image = Image.open(background_banner_file)
        foreground = Image.open(foreground_banner_file)
        # Fonts
        font1file = "%s/%s"%(theme,Theme.font1_banner[0])
        font1size = Theme.font1_banner[1]
        font1colour = Theme.font1_banner[2]
        font2file = "%s/%s"%(theme,Theme.font2_banner[0])
        font2size = Theme.font2_banner[1]
        font2colour = Theme.font2_banner[2]
        font3file = "%s/%s"%(theme,Theme.font3_banner[0])
        font3size = Theme.font3_banner[1]
        font3colour = Theme.font3_banner[2]
        
        # Open icon images
        acid = Image.open("%s/Icons/Aliens/Acid_Tube.png"%(image_folder))
        hive = Image.open("%s/Icons/Aliens/Hive.png"%(image_folder))
        om = Image.open("%s/Icons/Aliens/Overmind.png"%(image_folder))
        poison = Image.open("%s/Icons/Aliens/Booster.png"%(image_folder))
        granger = Image.open("%s/Icons/Aliens/Advanced_Granger.png"%(image_folder))
        dretch = Image.open("%s/Icons/Aliens/Dretch.png"%(image_folder))
        basi = Image.open("%s/Icons/Aliens/Advanced_Basilisk.png"%(image_folder))
        mara = Image.open("%s/Icons/Aliens/Advanced_Marauder.png"%(image_folder))
        goon = Image.open("%s/Icons/Aliens/Advanced_Dragoon.png"%(image_folder))
        tyrant = Image.open("%s/Icons/Aliens/Tyrant.png"%(image_folder))
        
        blaster = Image.open("%s/Icons/Humans/Blaster.png"%(image_folder))
        rifle = Image.open("%s/Icons/Humans/Rifle.png"%(image_folder))
        saw = Image.open("%s/Icons/Humans/Painsaw.png"%(image_folder))
        shotgun = Image.open("%s/Icons/Humans/Shotgun.png"%(image_folder))
        chaingun = Image.open("%s/Icons/Humans/Chaingun.png"%(image_folder))
        flamethrower = Image.open("%s/Icons/Humans/Flamer.png"%(image_folder))
        lasgun = Image.open("%s/Icons/Humans/Lasgun.png"%(image_folder))
        massdriver = Image.open("%s/Icons/Humans/Mass_Driver.png"%(image_folder))
        pulserifle = Image.open("%s/Icons/Humans/Pulse_Rifle.png"%(image_folder))
        grenade = Image.open("%s/Icons/Humans/Grenade.png"%(image_folder))
        lucifer = Image.open("%s/Icons/Humans/Lucifer_Cannon.png"%(image_folder))
        turret = Image.open("%s/Icons/Humans/Turret.png"%(image_folder))
        tesla = Image.open("%s/Icons/Humans/Tesla.png"%(image_folder))
        reactor = Image.open("%s/Icons/Humans/Reactor.png"%(image_folder))
        
        draw = ImageDraw.Draw(image)
        # Fonts
        font1 = ImageFont.truetype(font1file, font2size)
        font2 = ImageFont.truetype(font2file, font2size)
        font3 = ImageFont.truetype(font3file, font3size)
        # Get All Kills as dict
        kills = StatsFunctions().AllTimeKills()
        if gamekills_only:
            kills = StatsFunctions().KillStats()
        
        # Final Construction
        #Icons
        image.paste(blaster,Theme.blaster_co, blaster)
        image.paste(rifle,Theme.rifle_co, rifle)
        image.paste(saw,Theme.saw_co, saw)
        image.paste(shotgun,Theme.shotgun_co, shotgun)
        image.paste(chaingun,Theme.chaingun_co, chaingun)
        image.paste(flamethrower,Theme.flamethrower_co, flamethrower)
        image.paste(lasgun,Theme.lasgun_co, lasgun)
        image.paste(massdriver,Theme.massdriver_co, massdriver)
        image.paste(pulserifle,Theme.pulserifle_co, pulserifle)
        image.paste(lucifer,Theme.lucifer_co, lucifer)
        image.paste(grenade,Theme.grenade_co, grenade)
        
        image.paste(dretch,Theme.dretch_co, dretch)
        image.paste(basi,Theme.basi_co, basi)
        image.paste(mara,Theme.mara_co, mara)
        image.paste(goon,Theme.goon_co, goon)
        image.paste(tyrant,Theme.tyrant_co, tyrant)
        image.paste(poison,Theme.poison_co, poison)
        image.paste(granger,Theme.granger_co, granger)
        
        #Text
        draw.text(Theme.blaster_tc,str(kills['blaster']),font=font1, fill=font1colour)
        draw.text(Theme.rifle_tc,str(kills['rifle']),font=font1, fill=font1colour)
        draw.text(Theme.saw_tc,str(kills['saw']),font=font1, fill=font1colour)
        draw.text(Theme.shotgun_tc,str(kills['shotgun']),font=font1, fill=font1colour)
        draw.text(Theme.chaingun_tc,str(kills['chaingun']),font=font1, fill=font1colour)
        draw.text(Theme.flamethrower_tc,str(kills['flamethrower']),font=font1, fill=font1colour)
        draw.text(Theme.lasgun_tc,str(kills['lasgun']),font=font1, fill=font1colour)
        draw.text(Theme.massdriver_tc,str(kills['massdriver']),font=font1, fill=font1colour)
        draw.text(Theme.pulserifle_tc,str(kills['pulserifle']),font=font1, fill=font1colour)
        draw.text(Theme.lucifer_tc,str(kills['lucifer']),font=font1, fill=font1colour)
        draw.text(Theme.grenade_tc,str(kills['grenade']),font=font1, fill=font1colour)
        
        draw.text(Theme.dretch_tc,str(kills['dretch']),font=font1, fill=font1colour)
        draw.text(Theme.basi_tc,str(kills['lisk_gas']+kills['lisk_swipe']),font=font1, fill=font1colour)
        draw.text(Theme.mara_tc,str(kills['mara_claw']+kills['mara_zap']),font=font1, fill=font1colour)
        draw.text(Theme.goon_tc,str(kills['goon_pounce']+kills['goon_chomp']+kills['goon_snipe']),font=font1, fill=font1colour)
        draw.text(Theme.tyrant_tc,str(kills['tyrant_maul']+kills['tyrant_trample']),font=font1, fill=font1colour)
        draw.text(Theme.poison_tc,str(kills['poison']),font=font1, fill=font1colour)
        draw.text(Theme.granger_tc,str(kills['granger']),font=font1, fill=font1colour)
        if gamekills_only:
            kills = StatsFunctions().TotalKills()
            deaths = StatsFunctions().TotalDeaths()
            ratio = StatsFunctions().KillDeathRatio()
        else:
            kills = StatsFunctions().AllTimeTotalKills()
            deaths = StatsFunctions().AllTimeTotalDeaths()
            ratio = StatsFunctions().AllTimeRatio()
            
        draw.text(Theme.kills_tc, "Total Kills: %s"%(str(kills)),font=font3, fill=font3colour)
        draw.text(Theme.deaths_tc, "Total Deaths: %s"%(str(deaths)),font=font3, fill=font3colour)
        draw.text(Theme.ratio_tc, "Ratio: %s"%(str(ratio)),font=font3, fill=font3colour)
        
        # Draw name in colour
        if coloured_name:
            text = HelperFunctions().ColourText(name)
            co = Theme.name_tc
            for item in text:
                draw.text(co, item[0], font=font1,fill=item[1])
                co = (co[0]+draw.textsize(item[0],font=font1)[0],co[1])
        else:
            draw.text(Theme.name_tc,rendered_name,font=font2, fill=font2colour)
        # Add the time
        from time import strftime
        draw.text(Theme.time_tc,strftime("%a, %d %b %Y"), font=font2, fill=font2colour)
        if fg:
            image.paste(foreground,(0,0),foreground)
        image.save(banner_save)
        print "%s created!"%(banner_save.split('/')[-1])
        return banner_save, ftpbanner

    
    def WebPage(self,avatargloss=True,bannergloss=True,userbargloss=True,alone=False):
        """Create a web page of stats
        Set avatarglos, bannergloss and userbargloss to True if you want a foreground
        If alone is True, only the html page will be generated.
        If alone is False, all dependent objects will be generated"""
        
        # Template page
        template = open(htmlpage_template, 'r').read()        
        # Output page
        output = open(htmlpage_output, 'w')
        # Calculate whether ratio has increased or decreased
        # We need to find the last gaming session to compare the ratio with
        # For this, we use the graphdata file
        graphdata = open(graphdatafilename, 'r').readlines()
        # We need an accurate ratio so instead of using the archived
        # ratio which is to two decimal places, we will calculate it
        # ourselves using the kills and deaths
        try:
            newratio = int(graphdata[-1].split('/')[4]) /int(graphdata[-1].split('/')[5])
        # We need to check for division by zero errors
        except ZeroDivisionError:
            newratio = 0
        # Now we need to find the last gaming session. We do this
        # by comparing the time with minute resolution and move
        # backwards along the file until we find it
        line = -1
        same_session = True
        # While the times match, move backwards
        # We use a . to split the time to minute resolution
        # This might cause problems if the graphdata saves over more
        # than one minute but this should be a rare event
        while same_session:
            line -= 1
            same_session = graphdata[line].split('/')[0].split('.')[0][:-2] == graphdata[-1].split('/')[0].split('.')[0][:-2]
            
        # When we find the right line, we calculate the ratio
        try:
            oldratio = int(graphdata[line].split('/')[4]) /int(graphdata[line].split('/')[5])
        # We need to check for division by zero errors
        except ZeroDivisionError:
            oldratio = 0
        # Now we simply calculate the percentage change,
        # again checking for division by zero errors
        try:
            percent_change = (newratio - oldratio)/oldratio * 100
        except ZeroDivisionError:
            percent_change = newratio
        
        # If there is a positive change, player has improved, otherwise, he has not.
        if percent_change > 0:
            updown_image = "up"
        elif percent_change == 0:
            updown_image = "same"
        else:
            updown_image = "down"
        # If there is no change in ratio, a blank string is returned to keep output neat
        if percent_change == 0:
            percent_change = ""
        else:
            percent_change = "%.2f"%float(abs(percent_change)) + "%" # Percentage change is given to 2dp with a %
        
        # Dictionary of objects to replace with
        imagesdict = {'[human_icon]': 'Human','[alien_icon]': 'Overmind','[blaster_icon]':'Blaster','[dretch_icon]':'Dretch','[rifle_icon]':'Rifle','[lisk_swipe_icon]':'Advanced_Basilisk','[saw_icon]':'Painsaw','[lisk_gas_icon]':'Advanced_Basilisk','[shotgun_icon]':'Shotgun','[mara_claw_icon]':'Advanced_Marauder','[chaingun_icon]':'Chaingun','[mara_zap_icon]':'Advanced_Marauder','[flamethrower_icon]':'Flamer','[goon_chomp_icon]':'Advanced_Dragoon','[lasgun_icon]':'Lasgun','[goon_pounce_icon]':'Advanced_Dragoon','[massdriver_icon]':'Mass_Driver',
                        '[goon_snipe_icon]':'Advanced_Dragoon','[pulserifle_icon]':'Pulse_Rifle','[tyrant_maul_icon]':'Tyrant','[lucifer_icon]':'Lucifer_Cannon','[tyrant_trample_icon]':'Tyrant','[grenade_icon]':'Grenade','[granger_icon]':'Advanced_Granger','[poison_icon]':'Booster','[turret_icon]':'Turret','[tube_icon]':'Acid_Tube','[tesla_icon]':'Tesla','[hive_icon]':'Hive','[explosion_icon]':'Explosion','[acid_icon]':'Acid_Tube','[reactor_icon]':'Reactor','[overmind_icon]':'Overmind','[gravity_icon]':'Gravity','[died_icon]':'Died',
                        '[updown_image]':updown_image}
        # Replace template text
        template = HelperFunctions().ReplaceValues(template)
        # Check what type userbar is
        if len(stats_list) == 1:
            ftpuserbar = ftpuserbar_image
        else:
            ftpuserbar = ftpuserbar_anim
        for item in imagesdict:
            template = template.replace(item,str('<img src="img/icons/%s.png" alt="%s">'%(imagesdict[item],imagesdict[item])))
        objectsdict = {'[website_url]':website_url + "/",'[banner_image]':ftpbanner,'[avatar_image]':ftpavatar,'[userbar_image]':ftpuserbar,'[graph_all]':ftpgraph_all,'[graph_allkills]':ftpgraph_allkills,'[graph_alldeaths]':ftpgraph_alldeaths,'[graph_ratio]':ftpgraph_ratio,'[graph_allratio]':ftpgraph_allratio,'[graph_deaths]':ftpgraph_deaths,'[graph_kills]':ftpgraph_kills,'[graph_live]':ftpgraph_live,'[graph_piekills]':ftpgraph_piekills,'[graph_piedeaths]':ftpgraph_piedeaths,'[updown_alltimeratio]':percent_change}
        for item in objectsdict:
            template = template.replace(item, str(objectsdict[item]))
        print >> output,template
        if alone <> True: # If the webpage is to be generated alone, ignore all of this.
            template_original = open(htmlpage_template, 'r').read()
            # Dictionary of placeholders and functions to create the objects
            extras = {'[graph_all]':'self.Graph("all")','[graph_allkills]':'self.Graph("allkills")','[graph_alldeaths]':'self.Graph("alldeaths")','[graph_kills]':'self.Graph("kills")','[graph_deaths]':'self.Graph("deaths")','[graph_ratio]':'self.Graph("ratio")','[graph_allratio]':'self.Graph("allratio")','[graph_live]':'self.Graph("live")','[graph_piekills]':'self.Graph("piekills")','[graph_piedeaths]':'self.Graph("piedeaths")','[banner_image]':'self.Banner(bannergloss)','[avatar_image]':'self.Avatar(avatargloss)','[userbar_image]':'self.Userbar(userbargloss)'}
            number = 0
            # Loop through the extras and if they are called in the html template, we will create them.
            for item in extras:
                if item in template_original: # If the item is in the template
                    # If there are multiple graphs, reuse variables.
                    # We cannot reuse the live and pie chart variables
                    if "graph" in item and "live" not in item and "pie" not in item:
                        if number == 0: # If this is the first graph to be created, we initiate the variables
                            exec(extras[item].replace(")",",status=0)")) # We use exec here because the functions are stored as strings in the dictionary.
                            number = 1
                        else: # Otherwise, we reuse the variables
                            exec(extras[item].replace(")",",status=1)")) # We use exec here because the functions are stored as strings in the dictionary.
                    else: # When we don't have a 'graph', we just execute without bothering to reuse variables
                        exec(extras[item]) # We use exec here because the functions are stored as strings in the dictionary.
                    
        
        print "%s created!"%(htmlpage_output.split('/')[-1])
        
        return htmlpage_output,ftphtmlpage
    
    
    def Graph(self,graph=all,legend=True,show=False,status=2):
        """Graph against time. Must be used with SaveGraphData() or SaveLiveData()
        graph is the type of graph you want. Set graph to something random for a list
        If legend is True, a graph legend will be added
        If show is True, the graph will be displayed instead of saved
        Use status=0 for first operation on multiple graphs
        status=1 to continue operation
        status=2 to do a standalone graph"""
        
        import dateutil,pylab
        from matplotlib.dates import HourLocator,MinuteLocator,WeekdayLocator,MonthLocator,YearLocator
        if graph not in ("live","piekills","piedeaths"):#for most graphs, you need to get the graph data from graphdatafilename
            # Get graph data
            graph_data = open(graphdatafilename, 'r')
            graph_data = graph_data.readlines()
            # If more than one graph operation, then status=0 is the start, 1, is for successive operations
            if status == 0:
                global dates_strings, kills, deaths, ratio, allkills, alldeaths, allratio, range, major, minor, dates
            if status <> 1: # For status 0 and 2, variables need to be set
                dates_strings = []
                kills = []
                deaths = []
                ratio = []
                allkills = []
                alldeaths = []
                allratio = []
                try:
                    for line in graph_data:
                        dates_strings.append(line.split('/')[0])
                        dates = [dateutil.parser.parse(s) for s in dates_strings] # convert to date format
                        kills.append(int(line.split('/')[1]))
                        deaths.append(int(line.split('/')[2]))
                        ratio.append(float(line.split('/')[3]))
                        allkills.append(int(line.split('/')[4]))
                        alldeaths.append(int(line.split('/')[5]))
                        allratio.append(float(line.split('/')[6]))
                except IndexError:
                    print "Periodical Stats not found. Please check %s."%(graphdatafilename)
                    sys.exit()
                # Calculate range of dates
                range =  pylab.date2num(dates[-1]) - pylab.date2num(dates[0])
            
            
                if range < 1:
                    major = HourLocator() # every hour
                    minor = MinuteLocator() # every minute
                elif range < 30:
                    major = WeekdayLocator(byweekday=(1,2,3,4,5,6,7)) # every day
                    minor = HourLocator() # every hour
                elif range < 100:
                    major = WeekdayLocator(byweekday=1) # every monday and thursday
                    minor = WeekdayLocator(byweekday=(1,2,3,4,5,6,7)) # every day
                elif range < 150:
                    major = MonthLocator()   # every month
                    minor = WeekdayLocator(interval=2)  # every alternate monday
                elif range < 360:
                    major = MonthLocator(interval=2) # every alternate monday
                    minor = MonthLocator() # every month
                else:
                    major = YearLocator()
                    minor = MonthLocator()
        # Create canvas
        if graph in ("piekills","piedeaths"): # Need a square graph
            fig = pylab.figure(figsize=(8,8))
            ax = pylab.axes([0.12, 0.12, 0.8,0.8])
        else:
            fig = pylab.figure()
            ax = fig.add_subplot(111)
        if graph not in ("live","piekills","piedeaths"):
            ax.xaxis.set_major_locator(major)
            ax.xaxis.set_minor_locator(minor)
        if graph == "all":
            graph_out = graph_all
            ftpgraph = ftpgraph_all
            pylab.plot_date(pylab.date2num(dates), allkills, '-', color=Theme.allkills_colour)
            pylab.plot_date(pylab.date2num(dates), alldeaths, '-', color=Theme.alldeaths_colour)
            pylab.plot_date(pylab.date2num(dates), kills, '-', color=Theme.kills_colour)
            pylab.plot_date(pylab.date2num(dates), deaths, '-', color=Theme.deaths_colour)
            if legend:
                pylab.text(0,-0.25,"Kills per Session", color=Theme.kills_colour,va="center",ha="center",transform = ax.transAxes)
                pylab.text(0.25,-0.25,"Deaths per Session", color=Theme.deaths_colour,va="center",ha="center",transform = ax.transAxes)
                pylab.text(0.47,-0.248,"Overall Kills", color=Theme.allkills_colour,va="center",ha="center",transform = ax.transAxes)
                pylab.text(0.66,-0.248,"Overall Deaths", color=Theme.alldeaths_colour,va="center",ha="center",transform = ax.transAxes)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Stats',fontweight="bold")
            title = "Graph of Kills and Deaths over Time"
        elif graph == "allkills":
            graph_out = graph_allkills
            ftpgraph = ftpgraph_allkills
            pylab.plot_date(pylab.date2num(dates), allkills, '-', color=Theme.allkills_colour)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Total Kills',fontweight="bold")
            title = "Graph of Total Kills over Time"
        elif graph == "alldeaths":
            graph_out = graph_alldeaths
            ftpgraph = ftpgraph_alldeaths
            pylab.plot_date(pylab.date2num(dates), alldeaths, '-', Theme.alldeaths_colour)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Total Deaths',fontweight="bold")
            title = "Graph of Total Deaths over Time"
        elif graph == "kills":
            graph_out = graph_kills
            ftpgraph = ftpgraph_kills
            pylab.plot_date(pylab.date2num(dates), kills, '-', color=Theme.kills_colour)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Single Game Kills',fontweight="bold")
            title = "Graph of Kills per Game over Time"
        elif graph == "deaths":
            graph_out = graph_deaths
            ftpgraph = ftpgraph_deaths
            pylab.plot_date(pylab.date2num(dates), deaths, '-', color=Theme.deaths_colour)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Single Game Deaths',fontweight="bold")
            title = "Graph of Deaths per Game over Time"
        elif graph == "ratio":
            graph_out = graph_ratio
            ftpgraph = ftpgraph_ratio
            pylab.plot_date(pylab.date2num(dates), ratio, '-', color=Theme.ratio_colour)
            pylab.plot_date(pylab.date2num(dates), allratio, '-', color=Theme.allratio_colour)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Ratio',fontweight="bold")
            if legend:
                pylab.text(0,-0.25,"Ratio Per Session", color=Theme.ratio_colour,va="center",ha="center",transform = ax.transAxes)
                pylab.text(0.23,-0.25,"Overall Ratio", color=Theme.allratio_colour,va="center",ha="center",transform = ax.transAxes)

            title = "Graph of Player Ratio over Time"
        elif graph == "allratio":
            graph_out = graph_allratio
            ftpgraph = ftpgraph_allratio
            pylab.plot_date(pylab.date2num(dates), allratio, '-', color=Theme.allratio_colour)
            pylab.xlabel('Date',fontweight="bold")
            pylab.ylabel('Overall Ratio',fontweight="bold")
            title = "Graph of Overall Ratio over Time"
        elif graph == "live":
            graph_out = graph_live
            ftpgraph = ftpgraph_live
            try:
                live_data = open(livedatafilename,'r')
            except IOError:
                print "Live graph file not found. Please check %s."%(livedatafilename)
                sys.exit()
            live_times = []
            live_kills = []
            live_deaths = []
            live_ratio = []
            try:
                for line in live_data:
                    live_times.append(float(line.split('/')[0]))
                    live_kills.append(int(line.split('/')[1]))
                    live_deaths.append(int(line.split('/')[2]))
                    live_ratio.append(float(line.split('/')[3]))
            except IndexError:
                print "Live graph stats not found. Please check %s."%(livedatafilename)
                sys.exit()

            pylab.plot(live_times,live_kills,'-',color=Theme.live_kills_colour)
            pylab.plot(live_times, live_deaths, '-', color=Theme.live_deaths_colour)
            pylab.xlabel('Time (mins)',fontweight="bold")
            pylab.ylabel('Stats',fontweight="bold")
            ax2 = pylab.twinx()
            pylab.plot(live_times, live_ratio, '-', color=Theme.live_ratio_colour)
            pylab.ylabel('Ratio',fontweight="bold")
            ax2.yaxis.tick_right()
            if legend:
                pylab.text(0,-0.11,"Kills", color=Theme.live_kills_colour,va="center",ha="center",transform = ax.transAxes)
                pylab.text(0.1,-0.11,"Deaths", color=Theme.live_deaths_colour,va="center",ha="center",transform = ax.transAxes)
                pylab.text(0.2,-0.11,"Ratio", color=Theme.live_ratio_colour,va="center",ha="center",transform = ax.transAxes)
            title = "Graph of the last gaming session"
        elif graph in ("piekills","piedeaths"):
            if graph == "piekills": # Which stats should we use?
                graph_out = graph_piekills # Initiate variables for particular stats
                ftpgraph = ftpgraph_piekills
                dict = StatsFunctions().AllTimeKills()
                total_stats = StatsFunctions().AllTimeTotalKills()
                pie_colours = Theme.piekills_colours
                pie_shadow = Theme.piekills_shadow
                title = "Pie chart showing your weapon usage"
            else:
                graph_out = graph_piedeaths
                ftpgraph = ftpgraph_piedeaths
                dict = StatsFunctions().AllTimeDeaths()
                total_stats = StatsFunctions().AllTimeTotalDeaths()
                pie_colours = Theme.piedeaths_colours
                pie_shadow = Theme.piedeaths_shadow
                title = "Pie chart showing how you die"
            
            
            # Stats values sorted in descending order
            dict_keys = [item[0] for item in HelperFunctions().SortDict(dict)]
            
            # Calculate average value for aesthetic uses
            average_value = total_stats / len(dict_keys)
            
            # Slice fractions and labels
            fractions = []
            labels = []
            others = 0
            # If the weapon's value is bigger than the average, it can have it's own slice
            for item in dict_keys:
                if dict[item] > average_value:
                    fractions.append(dict[item])
                    labels.append(StatsFunctions().weapons_dict[item][0])
                else:
                    others = others + dict[item]
            # Add "Others" slice
            fractions.append(others)
            labels.append('Others')
            # Explode biggest slice and not the rest
            explodes = [0.1]
            explodes.extend([0]*(len(fractions)-1))

            # Function to label only big slices
            def SliceValue(key):
                return int(round(key/100 * total_stats,0)) # Get actual value for weapon
            
            pylab.pie(fractions, colors=pie_colours, labels=labels, explode=explodes, autopct=SliceValue, shadow=pie_shadow)

        else:
            print "Incorrect Argument Specified. One of live, all, kills, deaths, allkills, alldeaths, ratio, allratio"
            sys.exit()
        
        # Add title
        pylab.text(0.5,1.05,rendered_name + " - " + title,fontweight="bold",ha="center",transform = ax.transAxes)
        
        # Format x axis dates so that they look nice (slant)
        if graph == "live":
            pylab.text(1.1,-0.1,"Powered by TremCS",alpha=0.5, color="black",va="bottom",ha="right",transform = ax.transAxes)
        elif graph in ("piekills","piedeaths"):
            pylab.text(1,-0.1,"Powered by TremCS",alpha=0.5, color="black",va="bottom",ha="right",transform = ax.transAxes)
        else:
            pylab.text(1.1,-0.2,"Powered by TremCS",alpha=0.5, color="black",va="bottom",ha="right",transform = ax.transAxes)
            fig.autofmt_xdate()
        if show:
            pylab.show()
        else:
            pylab.savefig(graph_out)
        print "%s created!"%graph_out.split('/')[-1]
        return graph_out, ftpgraph

class Interfaces:
    """UIs and print to file functions"""
    
    
    def GetVersion(self):
        """Get the latest version"""
        print "Python version:",sys.version[0:5]
        print  "TremCS build:",__version__
        print
        # Try to get latest version information
        try:
            import urllib
            # This file will be updated with every svn build
            versioncheck = urllib.urlopen('http://tremcs.googlecode.com/svn/trunk/latest_build')
            versioncheck = int(versioncheck.read())
            if versioncheck > __version__:
                print "You have an old version. The latest is build %s."%(versioncheck)
            elif versioncheck < __version__:
                print "You have a beta version! Enjoy the breakage ;)"
            else:
                print "You have the latest version. Have fun =)"
        except:
            print "Could not get latest version information. Are you connected to the internet?"
        # Return info for other functions
        return (versioncheck,__version__)
    
    def HelpText(self,error=False,adv=False):
        """Help for the text interface"""
        
        print """    TremCS is a python script which collects your personal stats
    and outputs banners, graphs and a nice web page.

    Usage: python tremcs.py [options] [-u] [-i]

    All arguments to arguments can be left blank with the long version.
    eg: --avatar=
    """
        print """
    -h, -?  --help              Prints this help message.
            --name              Prints the detected tremulous name and it's uncoloured version.
    -e      --export            Save stats for later use. IMPORTANT!
    -E      --export-dnd        As above but don't destroy dump file.
    -X      --export-dump       Export relevant information to the stats file. 
            --dump-all          As above but dump everything.
                                
    -S      --save-graph        Export Graph Data to graphdata file. IMPORTANT!
                                Needed before --graph.

    -1      --live=x            Save live data every x seconds.
    -T      --teamstats=x       Output statistics for teams every x seconds.

            --playerstats=x     Output statistics for a player every x seconds.
            
            --allplayers=       Prints statistics for all players in game. 
                                Options are one of ratio,kills,deaths,sratio,
                                skills,sdeaths
            
    -a      --avatar=           Creates an Avatar with or without foreground 
                                layer. 
                                
                                Requires extra arguments. (Set in config.py)
    -b      --banner=           Creates a Banner with or without foreground 
                                layer. 
                                
                                Requires extra arguments. (Set in config.py)
    -U      --userbar=          Creates a userbar with or without foreground
                                layer.
                                
                                (Requires extra arguments. (Set in config.py)
    -g      --graph=            Creates a graph. Requires extra arguments.
                                One of: live, all, allkills, alldeaths, ratio,
                                kills, deaths, piekills, piedeaths
                                
    -p      --webpage           Creates a webpage.
    
    -w      --web=              Creates a webpage along with graphs and images.
                                Requires extra arguments.
                                1 for foreground, 0 for no foreground. 
                                eg: 11 puts a foreground on avatar and banner.
                                
    -u      --upload            Uploads object after creation.(Set in config.py)
    -i      --ignore            Suppress warning messages.
    -v      --version           Prints current TremCS version and checks for
                                updates.

    -A      --advanced-opts     Print Advanced Options

            --about             Prints info about TremCS
    """
        if adv:
            print """
    Advanced Options:
    
    -c      --command=          Run a command inside tremcs
    -k      --kills             Print Kills during game.
    -d      --deaths            Print Deaths during game.
    -r      --ratio             Print Ratio during game.
    -x      --killstats         Prints Kill Stats as a dictionary during game.
    -y      --deathstats        Prints Death Stats as a dictionary during game.

            --sessionkills      Print Kills during gaming session.
            --sessiondeaths     Print Deaths during gaming session.
            --sessionratio      Print Ratio during gaming session.
            --skillstats        Prints Kill Stats for current session.
            --sdeathstats       Prints Death Stats for current session.

    -K      --totalkills        Print All Time Kills.
    -D      --totaldeaths       Print All Time Deaths.
    -R      --totalratio        Print All Time Ratio.
    -s      --totalkillstats    Print All Time Kill Stats as python dictionary.
    -t      --totaldeathstats   Print All Time Death Stats as python dictionary.

    -F      --fav-weapon        Print Favourite Weapon.
    -L      --leastfav-weapon   Print Least Favourite Weapon.
    -Q      --quotes            Print random quotes made by you.
                                Use with --export-dump.
    -W      --weapon=           Print stats for a particular weapon.
                                Use --weapon= for a list.
    -o      --weapon-live=      Print stats for a weapon during session.
    """
        if error:
            print "!! Error. Incorrect Arguments. !!"
    def TextInterface(self):
        """Function to control tremcs via a text console"""
        import getopt
        global warn, save_stats
        if len(sys.argv) == 1:
            self.HelpText()
        try:
            opts, arg = getopt.getopt(sys.argv[1:], 'c:?QpXO:AT:U:G1:heuESa:b:g:w:ivkdrxyKDRstFLW:o:' ,["command=","name","quotes","webpage","playerstats=","allplayers=","dump-all","export-dump","other=","advanced-opts","userbar=","teamstats=","skillstats","sdeathstats","sessionkills","sessiondeaths","sessionratio","live-graph", "live=", "ignore","about", "upload", "help","export","export-dnd","save-graph","avatar=","banner=","graph=","web=","version","kills","deaths","ratio","killstats","deathstats","totalkills","totaldeaths","totalratio","totalkillstats","totaldeathstats","fav-weapon","leastfav-weapon","weapon=", "weapon-live="])
        except getopt.GetoptError:
            self.HelpText(True)
            sys.exit()
        up = '-u' in sys.argv or '--upload' in sys.argv # Catch upload argument
        if '-i' in sys.argv or '--ignore' in sys.argv: # Catch ignore errors argument
            warn = False
        
        for option,argument in opts:
            if option in ("-h","-?", "--help"):
                self.HelpText()
                sys.exit()
            if option in ("-A", "--advanced-opts"):
                self.HelpText(adv=True)
            if option in ("-e", "--export"):
                InputOutput().WriteQuickStats()
                save_stats = True
                
            if option in ("-E", "--export-dnd"):
                InputOutput().WriteQuickStats(False)
                save_stats = True
            if option in ("-X", "--export-dump"):
                InputOutput().ExportToStats()
            if option == "--dump-all":
                InputOutput().ExportToStats(False,True)
            if option in ("-S", "--save-graph"):
                InputOutput().SaveGraphData()
            if option in ("-a", "--avatar"):
                if argument == "1":
                    if up:
                        Networking().UploadViaFTP(Creators().Avatar(True))
                    else:
                        Creators().Avatar(True)
                elif argument == "0":
                    if up:
                        Networking().UploadViaFTP(Creators().Avatar(False))
                    else:
                        Creators().Avatar(False)
                else:
                    if up:
                        Networking().UploadViaFTP(Creators().Avatar(Theme.avatar_fg))
                    else:
                        Creators().Avatar(Theme.avatar_fg)
                        
            if option in ("-b", "--banner"):
                if argument == "1":
                    if up:
                        Networking().UploadViaFTP(Creators().Banner(True))
                    else:
                        Creators().Banner(True)
                elif argument == "0":
                    if up:
                        Networking().UploadViaFTP(Creators().Banner(False))
                    else:
                        Creators().Banner(False)
                else:
                    if up:
                        Networking().UploadViaFTP(Creators().Banner(Theme.banner_fg))
                    else:
                        Creators().Banner(Theme.banner_fg)
                    
                    
            if option in ("-U", "--userbar"):
                if argument == "help":
                    HelperFunctions().ReplaceValues("help")
                else:
                    if argument == "1":
                        if up:
                            Networking().UploadViaFTP(Creators().Userbar(True))
                        else:
                            Creators().Userbar(True)
                    elif argument == "0":
                        if up:
                            Networking().UploadViaFTP(Creators().Userbar(False))
                        else:
                            Creators().Userbar(False)
                    else:
                        if up:
                            Networking().UploadViaFTP(Creators().Userbar(Theme.userbar_fg))
                        else:
                            Creators().Userbar(Theme.userbar_fg)
                            
            if option in ("-g", "--graph"):
                if up:
                    Networking().UploadViaFTP(Creators().Graph(argument))
                else:
                    Creators().Graph(argument)
            if option in ("-p","--webpage"):
                if up:
                    Networking().UploadViaFTP(Creators().WebPage(alone=True))
                else:
                    Creators().WebPage(alone=True)
            if option in ("-w", "--web"):
                if up:
                    try:
                        for item in argument:
                            if item == "0":
                                arg.append(False)
                            else:
                                arg.append(True)
                        Networking().UploadWebPage(int(arg[0]),int(arg[1]),int(arg[2]))
                    except IndexError:
                        Networking().UploadWebPage(Theme.avatar_fg,Theme.banner_fg,Theme.userbar_fg)
                else:
                    try:
                        for item in argument:
                            if item == "0":
                                arg.append(False)
                            else:
                                arg.append(True)
                        Creators().WebPage(int(arg[0]),int(arg[1]),int(arg[2]))
                    except IndexError:
                        Creators().WebPage(Theme.avatar_fg,Theme.banner_fg,Theme.userbar_fg)
            if option in ("-v", "--version"):
                self.GetVersion()
            if option == "--about":
                print """
88888888888                             .d8888b.   .d8888b.  
    888                                d88P  Y88b d88P  Y88b 
    888                                888    888 Y88b.      
    888  888d888 .d88b.  88888b.d88b.  888         "Y888b.   
    888  888P"  d8P  Y8b 888 "888 "88b 888            "Y88b. 
    888  888    88888888 888  888  888 888    888       "888 
    888  888    Y8b.     888  888  888 Y88b  d88P Y88b  d88P 
    888  888     "Y8888  888  888  888  "Y8888P"   "Y8888P"  
                                                                 
Made by Durand: durand.co.nr

With thanks to:

%s
    """%__credits__
                import time
                if time.strftime('%H') < 12:
                    print "Good Morning!"
                elif time.strftime('%H') < 17:
                    print "Good Afternoon!"
                else:
                    print "Good Evening!"
            
            if option in ("-k", "--kills"):
                print StatsFunctions().GameKills()
            if option in ("-d", "--deaths"):
                print StatsFunctions().GameDeaths()
            if option in ("-x", "--killstats"):
                print StatsFunctions().GameKillStats()
            if option in ("-y", "--deathstats"):
                print StatsFunctions().GameDeathStats()
            if option in ("-r", "--ratio"):
                print StatsFunctions().GameRatio()
            if option in ("-K", "--totalkills"):
                print StatsFunctions().AllTimeTotalKills()
            if option in ("-D", "--totaldeaths"):
                print StatsFunctions().AllTimeTotalDeaths()
            if option in ("-R", "--totalratio"):
                print StatsFunctions().AllTimeRatio()
            if option in ("-s", "--totalkillstats"):
                print StatsFunctions().AllTimeKills()
            if option in ("-t", "--totaldeathstats"):
                print StatsFunctions().AllTimeDeaths()
            if option in ("-F", "--fav-weapon"):
                print StatsFunctions().FavWeapon()[1]
            if option in ("-L", "--leastfav-weapon"):
                print StatsFunctions().FavWeapon(1)[1]
            if option in ("-Q", "--quotes"):
                print StatsFunctions().FavQuote()
            if option in ("-W", "--weapon"):
                StatsFunctions().GetWeapon(argument)
            if option in ("-o", "--weapon-live"):
                StatsFunctions().GetLiveWeapon(argument)
            if option in ("-1", "--live"):
                InputOutput().SaveLiveData(float(argument))
            if option in ("--sessionkills"):
                print StatsFunctions().TotalKills()
            if option in ("--sessiondeaths"):
                print StatsFunctions().TotalDeaths()
            if option in ("--sessionratio"):
                print StatsFunctions().Ratio()
            if option in ("--skillstats"):
               print StatsFunctions().KillStats()
            if option in ("--sdeathstats"):
                print StatsFunctions().DeathStats()
            if option in ("-T","--teamstats"):
                InGameFunctions().OutputTeamStats(float(argument))
            if option in ("-O", "--other"):
                global name,gamekills_only
                name = InGameFunctions().OtherPlayers(argument)[0]
                print name
                gamekills_only = True
                print "Player: ",InGameFunctions().OtherPlayers(argument)[1][0]
            if option == "--playerstats":
                InGameFunctions().GetPlayer(float(argument))
            if option == "--allplayers":
                InGameFunctions().AllPlayers(argument)
            if option in ("-c","--command"):
                exec(argument)

if __name__ == "__main__":
    try:
        Interfaces().TextInterface()
        global updates
        updates = True
    except KeyboardInterrupt:        
        print "Goodbye!"
    

